# ps2.s
# connect4-nios2 project
#
# ps/2 input functions
# - keyboard input and buffering
#
.equ PS2_ADDR, 0xff1150
.equ ADDR_7SEG, 0xff1100

.data

ps2_in_buf:		.skip 8

.global PS2_SEND
.global PS2_RECV
.global PS2_STOR_BUF
.global PS2_CLEAR_BUF
.global PS2_READ_DATA
.global PS2_GET_BUF_BYTE_1
.global PS2_GET_BUF_BYTE_2
.global PS2_CHECK_INT
.global PS2_SET_INT
.text

PS2_SEND:
	# send r4 to ps2
	subi sp, sp, 4
	stw ra, 0(sp)

	movia r8, PS2_ADDR

	# do something!! <-----

	ldw ra, 0(sp)
	addi sp, sp, 4
	ret

PS2_RECV:
	# read a char from PS2 into r2 (poll until)
	subi sp, sp, 4
	stw ra, 0(sp)

	movia r8, PS2_ADDR
	PS2_R_W1:
		ldwio r9, 0(r8)
		andi r10, r9, 0xffff0000	# get upper half
		beq r10, r0, PS2_R_W1	# poll until we have something to read
	andi r2, r9, 0xff		# get char data into r2

	ldw ra, 0(sp)
	addi sp, sp, 4
	ret

PS2_READ_DATA:
	# read a char from PS2 into r2 (poll until)
	subi sp, sp, 12
	stw ra, 0(sp)
	stw r8, 4(sp)
	stw r9, 8(sp)

	movia r8, PS2_ADDR

	ldwio r9, 0(r8)
	andi r2, r9, 0xff		# get char data into r2

	ldw r8, 4(sp)
	ldw r9, 8(sp)
	ldw ra, 0(sp)
	addi sp, sp, 12
	ret

PS2_STOR_BUF:
	# store r4 char into ps2_in_buf
	subi sp, sp, 20
	stw ra, 0(sp)
	stw r8, 4(sp)
	stw r9, 8(sp)
	stw r7, 12(sp)
	stw r4, 16(sp)
	
	movia r8, ADDR_7SEG
	movia r9, ps2_in_buf
	
	ldw r7, 0(r9)		# load current buffer
	slli r7, r7, 8		# shift by a byte
	andi r4, r4, 0xff	# extract latest char
	or r7, r7, r4		# add it to the end of the buffer
	stw r7, 0(r9)		# save to buffer

	# write to 7segs
	stwio r7, 0(r8)

	ldw r8, 4(sp)
	ldw r9, 8(sp)
	ldw r7, 12(sp)
	ldw r4, 16(sp)
	ldw ra, 0(sp)
	addi sp, sp, 20
	ret

PS2_GET_BUF_BYTE_1:
	# returns the most recent byte stored in the ps2 read buffer
	subi sp, sp, 12
	stw ra, 0(sp)
	stw r9, 4(sp)
	stw r7, 8(sp)
	
	movia r9, ps2_in_buf

	# read from buffer
	ldw r7, 0(r9)		# load current buffer
	andi r2, r7, 0xff	# get first byte (check this) - return in r2

	ldw r9, 4(sp)
	ldw r7, 8(sp)
	ldw ra, 0(sp)
	addi sp, sp, 12
	ret

PS2_GET_BUF_BYTE_2:
	# returns the 2nd byte stored in the ps2 read buffer
	subi sp, sp, 12
	stw ra, 0(sp)
	stw r9, 4(sp)
	stw r7, 8(sp)
	
	movia r9, ps2_in_buf

	# read from buffer
	ldw r7, 0(r9)		# load current buffer
	andi r2, r7, 0xff00	# get second byte (check this) - return in r2
	srli r2, r2, 8		# shift a byte over

	ldw r9, 4(sp)
	ldw r7, 8(sp)
	ldw ra, 0(sp)
	addi sp, sp, 12
	ret

PS2_CLEAR_BUF:
	# clears the ps2 input storage buffer
	subi sp, sp, 8
	stw ra, 0(sp)
	stw r9, 4(sp)

	movia r9, ps2_in_buf

	stw r0, 0(r9)

	ldw r9, 4(sp)
	ldw ra, 0(sp)
	addi sp, sp, 8
	ret

PS2_SET_INT:
	# set-up interrupts instead of polling.
	subi sp, sp, 12
	stw ra, 0(sp)
	stw r16, 4(sp)
	stw r17, 8(sp)

	movia r16, PS2_ADDR

	movi r17, 1
	stwio r17, 4(r16)	# enable read interrupts on device

	movi r17, 0x800		# enable IRQ 11 (12th bit)
	WRCTL ctl3, r17

	# still need to enable master interrupts

	ldw r17, 8(sp)
	ldw r16, 4(sp)
	ldw ra, 0(sp)
	addi sp, sp, 12
	ret

PS2_CHECK_INT:
	# check if the ps/2 keboard flagged a read interrupt
	subi sp, sp, 12
	stw ra, 0(sp)
	stw r16, 4(sp)
	stw r17, 8(sp)

	movia r16, PS2_ADDR

	ldwio r16, 4(r16)	# get control reg of ps2

	movi r17, 0x100		
	and r17, r16, r17	# check bit 8

	mov r2, r0	# pre-set r2 to zero
	beq r0, r17, ps2_int_false	# jump to false if zero
	
	movi r2, 1	# return true

	ps2_int_false:

	ldw r17, 8(sp)
	ldw r16, 4(sp)
	ldw ra, 0(sp)
	addi sp, sp, 12
	ret

# eof
